热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

次序|更多_AspectJ——切入点语法之thistargetargsif以及逻辑运算

篇首语:本文由编程笔记#小编为大家整理,主要介绍了AspectJ——切入点语法之thistargetargsif以及逻辑运算相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了AspectJ——切入点语法之thistargetargsif以及逻辑运算相关的知识,希望对你有一定的参考价值。



更多的切入点语法

本节介绍AspectJ中更多的切入点语法,有很多在之前都用过,这里做一个总结。


0.捕获this引用的是特定类型对象的连接点

AspectJ提供了this原生切入点来捕获所有的连接点,这些连接点处的this引用的是一个特定的类型。

我们在Test13包下做测试,首先业务类Service如下:

package Test13;
public class Service
public int add(int a, int b)
return a + b;

public double square(double a)
return a * a;

public String upper(String string)
return string.toUpperCase();

其包含三个方法。测试类Main如下:

package Test13;
public class Main
public static void main(String[] args)
Service service = new Service();
System.out.println("service.add(1, 2) = " + service.add(1, 2));
System.out.println("service.square(6) = " + service.square(6));
System.out.println("service.upper(\\"Gavin\\") = " + service.upper("Gavin"));

接着我们定义切面ThisAspect,如下:

package Test13;
public aspect ThisAspect
pointcut thisPointcut(Service service): this(service);
before(Service service): thisPointcut(service)
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(service);

切面中,我们定义了thisPointcut(Service service)切入点,该切入点使用this(service)选择在源代码中this引用的是一个Service对象的连接点。在这里例子中,其实也就是所有在Service类中的连接点。运行结果如下:

通常情况下,this原生切入点和其他切入点配合使用,使在通知中可以使用当前this引用的对象。


1.使用target捕获目标对象是特定类型的连接点

this原生切入点类似,target原生切入点可以捕获所有目标对象是特定类型连接点。如在上例中,我们将切入点的this变成target:

package Test13;
public aspect ThisAspect
pointcut thisPointcut(Service service): target(service);
before(Service service): thisPointcut(service)
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(service);

此时,就会捕获所有目标对象是Service类对象的连接点,运行结果如下:

可以看到,多出来了Main类中的几个对Service类方法的调用连接点,因为这些连接点的目标对象是Service类的对象,所以都被捕获到。而其他的原本就在Service类中的连接点也依然被捕获到,它们的目标对象显然也是Service类对象。

target原生切入点通常也与其他切入点结合使用。


2.使用args捕获具有特定参数类型、参数次序和参数个数的连接点

使用args可以捕获具有特定参数类型、参数次序、参数个数的连接点。在args中也可以使用通配符,用以选择通配符指定的具有特定参数个数和次序的连接点。

我们在Test14包下做测试,业务类Service和测试类Main与上例一样,另外我们新建切面ArgsAspect,如下:

package Test14;
public aspect ArgsAspect
pointcut argsPointcut(): args(*, *);
before(): argsPointcut()
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());

我们使用args(*, *)选择具有两个参数的连接点。运行结果如下:

如果我们将args(*, *)换成args(*),那么就只会选择只有一个参数的通配符了:

package Test14;
public aspect ArgsAspect
pointcut argsPointcut(): args(*) && !within(ArgsAspect);
before(): argsPointcut()
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());

另外,还可以使用args(*, int),选择有两个参数,并且第二个参数是int类型的连接点;args(float, .., int)选择第一个参数是float类型,最后一个参数是int类型的,并且中间有任意个参数的连接点。

通常情况下,args通常和其他切入点一起使用,来获取连接点的参数,如下用法:

package Test14;
public aspect ArgsAspect
pointcut argsPointcut(int a, int b): call(* add(..)) && args(a, b);
before(int a, int b): argsPointcut(a, b)
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println("第一个参数是:" + a);
System.out.println("第二个参数是:" + b);

运行结果是:


3.切入点的与或非运算

切入点之间可以进行与或非运算,分别对应符号&&||!

&&表示同时满足多个切入点表达式的切入点。关于&&的示例前面见过很多,这里不再赘述。

||的意义也很明显,它可以让切入点选择多个不同的连接点。比如,我们将上面的例子修改如下:

public aspect ArgsAspect
pointcut argsPointcut(): call(* add(..)) || call(* square(..));
before(): argsPointcut()
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());

call(* add(..)) || call(* square(..))表示捕获对add方法的调用和对square方法的调用,运行结果如下:

!运算前面也用到过,其作用是取反,比如!withincode(* add(..))排除在add方法中的连接点,!within(ArgsAspect)排除在切面ArgsAspect中的连接点。另外,非运算也可以用在某一个方法签名的字段前面, 比如我们继续将上例修改如下:

public aspect ArgsAspect
pointcut argsPointcut(): execution(public !static * *(..));
before(): argsPointcut()
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());

切入点execution(public !static * *(..))表示所有非静态方法的执行连接点,也就是捕获除了public static void main(String[] args)方法之外的其他所有方法的执行连接点,运行结果如下:

如果将!static改为static,那么此时的运行结果为:

两者的区别显而易见。


4.使用if来设置连接点上的运行时条件

if原生切入点可以设置运行时条件,只有在if判断为true的时候,才捕获该连接点。语法是:

pointcut [切入点名字](要获取的参数): if(Boolean expression);

其具有两个关键特征:


  1. if(Boolean expression)切入点评估在运行时提供的变量,得到关于连接点是否应该触发相应通知的truefalse结果。
  2. expression可以由多个逻辑元素组成,包括展示的连接点环境、静态变量、以及其他切入点声明。

我们在Test15包下做一个简单的测试(这个测试可能不太符合常理,不过演示出效果即可),首先新建People类:

package Test15;
public class People
private String name;
private int age;
public People(String name, int age)
this.name = name;
this.age = age;

public String getName()
return name;

public void setName(String name)
this.name = name;

public void drive()
System.out.println(name + "不可以开车...");

其中它有属性nameage,另外其具有drive()开车方法,我们规定只有年龄大于18岁才可以开车,并且默认地认为当前对象不可以开车。所以我们新建切面,来捕获对drive()方法的执行,并为其织入环绕通知:

package Test15;
public aspect DriveAspect
pointcut drivePointcut():execution(void People.drive())
&& if((thisJoinPoint.getThis() instanceof People)
&& ((People)thisJoinPoint.getThis()).getAge() > 18);
void around():drivePointcut()
System.out.println(((People)thisJoinPoint.getThis()).getName() + "可以开车...");

在切入点drivePointcut中,我们捕获了对drive()方法的执行,并且只有在当前this引用的People对象的年龄大于18的时候,我们才捕获该切入点,此时在为其织入的环绕通知中,我们改变原来程序的运行逻辑,输出可以开车

接着,新建测试类Main如下:

package Test15;
public class Main
public static void main(String[] args)
People people = new People("Gavin", 17);
people.drive();

首先,我们设置“Gavin”的年龄为17岁,这时的运行结果是:

接着,假如我们设置“Gavin”的年龄为19岁,这时的运行结果为:

两个结果与我们的预期完全一样,说明我们使用if定义的切入点完全正确。


推荐阅读
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
author-avatar
情之秋梦痕
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有